#include <sys/epoll.h>
#include "mytcp.h"

/*========================================<工具函数>========================================*/


/*========================================<网络地址类>========================================*/
// 构造函数，初始化地址结构体
InetAddress::InetAddress()
{
    bzero(&addr, sizeof(addr));
    addr_len = sizeof(addr);
}

InetAddress::InetAddress(const char* ip, uint16_t port)
{
    // 初始化地址族为IPv4协议
    this->addr.sin_family = AF_INET;
    // 将主机字节序的端口号转换为网络字节序
    this->addr.sin_port = htons(port);
    // 将字符串形式的IPv4地址转换为网络地址
    inet_pton(AF_INET, ip, &this->addr.sin_addr);
    // 设置sockaddr_in结构体的大小
    addr_len = sizeof(this->addr);
}

InetAddress::~InetAddress() {}


/*========================================<socket套接字类>========================================*/

Socket::Socket() :fd(-1)
{
    this->fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0)
    {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    int optval = 1;
    if (setsockopt(this->fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0)
    {
        perror("setsockopt SO_REUSEADDR");
        exit(EXIT_FAILURE);
    }
}

Socket::Socket(int fd) :fd(fd)
{
    if (fd < 0)
    {
        perror("socket");
        exit(EXIT_FAILURE);
    }
}


Socket::~Socket()
{
    if (this->fd != -1)
        close(this->fd);
    fd = -1;
}

int Socket::getFd()const { return this->fd; }
void Socket::setFd(int fd) { this->fd = fd; }

void Socket::setnonblocking()
{
    fcntl(this->fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
}

void Socket::bind(InetAddress* inetAddr)
{
    if (::bind(this->fd, (sockaddr*)&inetAddr->addr, inetAddr->addr_len) < 0)
    {

        perror("bind");
        exit(EXIT_FAILURE);
    }
}

void Socket::listen(int backLog)
{
    int ret;
    ret = ::listen(this->fd, backLog);
    if (ret < 0)
    {
        // 处理监听失败的情况
        perror("listen");
        exit(EXIT_FAILURE);
    }
}

int Socket::accept(InetAddress* inetAddr)
{
    int clientFd = -1;
    // 接受客户端连接，获取客户端文件描述符
    clientFd = ::accept(this->fd, (sockaddr*)&inetAddr->addr, &inetAddr->addr_len);
    if (clientFd < 0)
    {
        perror("accept");
    }
    return clientFd;
}


ssize_t Socket::sendAll(const void* buf, size_t len)
{
    size_t total_sent = 0;
    const char* p = static_cast<const char*>(buf);
    while (total_sent < len)
    {
        ssize_t bytes_sent = ::send(fd, p + total_sent, len - total_sent, 0);
        if (bytes_sent < 0)
        {
            if (errno == EINTR) continue; // 被信号中断，继续发送
            if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                return -1;
            }
            perror("sendAll error");
            return -1;
        }
        else if (bytes_sent == 0)
        {
            return 0;
        }
        total_sent += bytes_sent;
    }
    return total_sent;
}

ssize_t Socket::recvAll(void* buf, size_t len)
{
    size_t total_received = 0;
    char* p = static_cast<char*>(buf);
    // 循环接收直到满足指定长度
    while (total_received < len)
    {
        ssize_t bytes_received = ::recv(fd, p + total_received, len - total_received, 0);
        if (bytes_received < 0)
        {
            // 被中断则继续接收
            if (errno == EINTR) continue;
            // 非阻塞情况下无数据可读，返回-1
            if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                return -1;
            }
            perror("recvAll error");
            return -1;
        }
        else if (bytes_received == 0)
        {
            // 对方关闭连接，返回已接收的数据量
            return total_received; // 返回已接收的数据量
        }
        total_received += bytes_received;
    }
    return total_received;
}

ssize_t Socket::recv(void* buf, size_t len)
{
    ssize_t bytes_received = ::recv(fd, buf, len, 0);
    if (bytes_received < 0)
    {
        // 处理各种错误情况
        if (errno == EINTR)
        {
            return -1;
        }
        // 非阻塞模式下无数据可读
        if (errno == EAGAIN || errno == EWOULDBLOCK)
        {
            return 0;
        }
        // 其他错误处理
        perror("Socket::recv error");
        return -1; // 其他错误
    }
    // 返回实际接收到的字节数
    return bytes_received;
}

/*========================================<epoll边缘触发类，IO多路复用>========================================*/

EpollET::EpollET() :epfd(-1)
{
    this->epfd = epoll_create1(0);
    if (epfd < 0) { perror("epoll_create1"); exit(1); }

    this->events = new struct epoll_event[MAX_EVENTS];
    bzero(events, sizeof(*events) * MAX_EVENTS);
}

EpollET::~EpollET()
{
    if (epfd != 0)
        close(epfd);

    delete[] events;
}

int EpollET::getEpfd()const { return this->epfd; }

int EpollET::add_fd(int fd, uint32_t op)
{
    struct epoll_event ev;
    ev.data.fd = fd;
    ev.events = op;

    if (epoll_ctl(this->epfd, EPOLL_CTL_ADD, fd, &ev) < 0) { perror("epoll_ctl"); return -1; }
    return 0;
}

std::vector<epoll_event> EpollET::poll(int timeout)
{
    std::vector<epoll_event> activeEvents;
    int nfds;
    nfds = epoll_wait(this->epfd, this->events, MAX_EVENTS, timeout);
    if (nfds < 0)
    {
        perror("epoll_wait");
        exit(1);
    }

    for (int i = 0;i < nfds;i++)
    {
        activeEvents.push_back(events[i]);
    }
    return activeEvents;

}